import Net from "../api/Net.js";
import Api from "../api/Api.js"
import Algo from "../utils/Algorithm.js"
import Db from "../db/Db.js"
import Drawer from "../drawer/Drawer.js"
import {ServiceType,LayerType} from '../db/SafeMonitorType.js'
import Type from "../db/Type.js";
import { URL } from "../../configure/Assets.js"
const Mine_Id = ServiceType.Mine_Id
export default class zTreeUtils {
    constructor() {
        if (zTreeUtils.instance) {
            return zTreeUtils.instance;
        }
        this.net = new Net()
        this.api = new Api()
        this.db = new Db()
        this.algo = new Algo()
        this.drawer = new Drawer()
        zTreeUtils.instance = this;

    }

    async getAllNodes(mine_id=Mine_Id) {
        return await this.net.get(`${URL.BASE_URL}/zTree`, { mine_id: mine_id });
    }
    // 获取全部井下广播站的结点
    async getAllBroadCastNodes(mine_id=Mine_Id,servicetype='admin',type='broadcast') {
        return await this.net.get(`${URL.BASE_URL}/zTreeAdmin`, { mine_id: mine_id,servicetype:servicetype,type });
    }

    // 获取已经被选择过的井下广播站的结点
    async getSelectedBroadCastNodes(mine_id=Mine_Id,type='broadcast') {
        return await this.net.get(`${URL.BASE_URL}/zTreeData`, { mine_id: mine_id,type });
    }

    // 根据地下广播站id 获取单个广播站的详细信息
    async getBroadcastInfo(node_id,serviceType) {
        return await this.net.get(`${URL.BASE_URL}/sm_info`, {node_id,serviceType});
    }

    // 获取全部安全监控的结点
    async getAllGasNodes() {
        return await this.net.get(`${URL.BASE_URL}/zTreeAdmin`, { mine_id: Mine_Id,servicetype:'admin',type: ServiceType.Gas });
    }

    // 获取已被选择的安全监控的结点
    async getSelectedGasNodes() {
        return await this.net.get(`${URL.BASE_URL}/zTreeData`, { mine_id: Mine_Id,type: ServiceType.Gas });
    }

    // 获取全部人员分站的结点
    async getAllStaffNodes(mine_id=Mine_Id,servicetype='admin',type='staff') {
        return await this.net.get(`${URL.BASE_URL}/zTreeAdmin`, { mine_id: mine_id,servicetype:servicetype,type });
    }

    // 获取已被选择的人员分站的结点
    async getSelectedStaffNodes(mine_id=Mine_Id,type="staff") {
        return await this.net.get(`${URL.BASE_URL}/zTreeData`, { mine_id: mine_id, type});
    }

    // 根据读卡器分站id去获取读卡器详细分站信息。
    async getStaffInfo(node_id,serviceType) {
        return await this.net.get(`${URL.BASE_URL}/sm_info`, {node_id,serviceType});
    }

    // 获取通风设备信息
    async getSmVentilation() {
        return await this.net.get(`${URL.BASE_URL}/ventilation`);
    }

    // 获取通风设备 的所有风向角度信息。有的就代表被设置过风向的。没有就代表没有被设置过风向。
    async getSmVentilation_rotation() {
        return await this.net.get(`${URL.BASE_URL}/ventilation_rotation`,{meta_id:'person'});
    }


    // 获取全部摄像头的结点
    async getAllVideoNodes(mine_id=Mine_Id,servicetype='admin',type='video') {
        return await this.net.get(`${URL.BASE_URL}/zTreeAdmin`, { mine_id: mine_id,servicetype:servicetype,type });
    }

    // 获取已被选择的摄像头的结点
    async getSelectedVideoNodes(mine_id=Mine_Id,type="video") {
        return await this.net.get(`${URL.BASE_URL}/zTreeData`, { mine_id: mine_id,type });
    }
    // 获取最新数据更新 indexDB中和安全监控相关的表格数据
    async PositionDbRefresh() {
        // 获取 m_position中的信息 进行更新
        const {data:newpositions} = await this.api.getSmPositions(ServiceType.Mine_Id)
        // 获取在自己的数据库里面存放着的断电区域的位置信息
        const areas = await this.api.getSmPoweredAreas()
        const currentVideoPos = newpositions.filter((po) => {
            return po.layer ==  LayerType.SMVideo
        })
        const currentStaffPos = newpositions.filter((po) => {
            return po.layer ==  LayerType.SMStaff
        })
        const currentBroadCastPos = newpositions.filter((po) => {
            return po.layer ==  LayerType.SMBroadCast
        })
        const currentGasPos = newpositions.filter((po) => {
            return po.layer ==  LayerType.SMGas
        })
        // 根据 筛选后的数据，去更新indexDb
        await this.db.refresh(LayerType.SMStaff,currentStaffPos)
        await this.db.refresh(LayerType.SMBroadCast,currentBroadCastPos)
        await this.db.refresh(LayerType.SMVideo,currentVideoPos)
        await this.db.refresh(LayerType.SMGas,currentGasPos)
        // indexDb更新完成以后，自动更新 gis图层上的内容
        await this.drawer._smstaff()
        await this.drawer._smbroadcast()
        // await this.drawer._smvideo()
        await this.drawer._smgas()
        this.drawer.initCluster()
    }

    // 获取 传感器与广播站，摄像头断点区域的关联关系
    async getGasintegration() {
        const res = await this.net.get(`${URL.BASE_URL}/integration`)
        return res
    }

    // 创建 gis元素高亮动画效果
    highLightAnimation(coordinate,time=3000,type='locate') {
        // 根据传入的 type 值确定，波纹动画效果 是定位时候的波纹还是报警时候的波纹
        var point_div = document.createElement('div');
        let AnimationClassname = ''
        if(type == 'locate') {
            AnimationClassname = 'css_animation_locate'
        }
        if(type == 'alarm') {
            AnimationClassname = 'css_animation_alarm'
        }
        if(type == 'warming') {
            AnimationClassname = 'css_animation_warming'
        }
        point_div.className= AnimationClassname;
        const point_overlay = new ol.Overlay({
            element: point_div,
            positioning: 'center-center',
            // 让鼠标点击可以穿透 overlay
            stopEvent:false
        });
        this.drawer.map.addOverlay(point_overlay);
        const deNormalCoordinate = [this.algo.normalX(coordinate[0]),this.algo.normalY(coordinate[1])]
        point_overlay.setPosition(deNormalCoordinate);
        const timer = setTimeout(() => {
            this.drawer.map.removeOverlay(point_overlay)
            point_div.remove()
            clearTimeout(timer)
        },time)
    }

    // 在这个地方再单独写一个坐标转换函数（因为原来的安全监控系统用的坐标系是自定义坐标系，需要转换）
    position_transform(data) {
        // 现在先不写，直接把数据进行返回。
        console.log('p-data',data)
        return Promise.resolve(data)
    }

    // 单击树节点的时候，进行元素在gis上的定位
    featureLocate(coordinate) {
        const view = this.drawer.map.getView()
        const denormalCoordinate = [this.algo.normalX(coordinate[0]),this.algo.normalY(coordinate[1])]
        view.setCenter(denormalCoordinate)
        this.highLightAnimation(coordinate)
    }

    // 用线条连接体现监控分站下 传感器的从属关系 (传入的node_id 必须是监控分站)
    highLightStationRelation(treenode) {
        const {node_id} = treenode
        const features = this.drawer.source(LayerType.SMGas).getFeatures()
        const childrenSensor = []
        let stationFeature = null
        features.forEach((f) => {
            if(f.get('parent_id') == node_id) {
                childrenSensor.push(f)
            }
            if(f.get('node_id') == node_id) {
                stationFeature = f
            }
        })
        const stationCoordinate = stationFeature.getGeometry().getCoordinates()
        const sensorChilrenCoordinate = childrenSensor.map((point) => {
            return point.getGeometry().getCoordinates()
        })
        const modifySource = this.drawer.source(Type.Modify)
        // const lineStyle = new ol.style.Style({
        //     fill: new ol.style.Fill({
        //         color: '#3399CC'
        //     })
        // })
        const insertFeatures = sensorChilrenCoordinate.map((co) => {
            const lineFe = new ol.Feature()
            const geom = new ol.geom.LineString([co,stationCoordinate])
            // lineStyle.getGeometry(geom)
            // lineFe.setStyle(lineStyle)
            lineFe.setGeometry(geom)
            return lineFe
        })
        modifySource.addFeatures(insertFeatures)
        const timer = setTimeout(() => {
            modifySource.clear()
            clearTimeout(timer)
        },3500)
    }

    // 用线条连接体现监控分站下 与传入传感器 属于同一个通道的所有传感器
    highLightSensorRelation(treenode) {
        const {sensor_Type,station_Id,node_id,channel_Code,channel_Id} = treenode
        const features = this.drawer.source(LayerType.SMGas).getFeatures()
        const nodes = []
        features.forEach((f) => {
            if(f.get('station_Id') == station_Id && f.get('channel_Id') == channel_Id) {
                nodes.push(f)
            }
        })
        // 按照 channelcode排序
        nodes.sort(function (a,b) {
            const a_code = a.get('channel_Code')
            const b_code = b.get('channel_Code')
            return a_code - b_code
        })

        const nodesCoordinate = nodes.map((point) => {
            return point.getGeometry().getCoordinates()
        })
        const multiLineCoordinates = []
        for(let i = 0;0 < nodesCoordinate.length; i++) {
            if(i == nodesCoordinate.length - 1) {
                break
            }
            multiLineCoordinates.push([nodesCoordinate[i],nodesCoordinate[i+1]])
        }

        const modifySource = this.drawer.source(Type.Modify)
        // const lineStyle = new ol.style.Style({
        //     fill: new ol.style.Fill({
        //         color: '#3399CC'
        //     })
        // })
        const multiLineFeature =  new ol.Feature()
        // debugger
        multiLineFeature.setGeometry(new ol.geom.MultiLineString(multiLineCoordinates))
        modifySource.addFeature(multiLineFeature)
        const timer = setTimeout(() => {
            modifySource.clear()
            clearTimeout(timer)
        },3500)
    }

    // 将gas树中的数据里面的 node_id 进行提取，提取出 传感器所属分站，通道编号，通道上的排序号等信息
    gasNodesInfoExtract(data) {
        data.forEach((el) => {
            // 根据node_id 确定传感器类型
            const node_id = el.node_id
            if(node_id.length != 3) {
                el.type = '传感器'
                el.station_Id = node_id.slice(0,3) // 截取获取传感器 所属的监控分站的id
                el.channel_Id = node_id.slice(3,5) // 截取获取传感器 在对应监控分站上的通道号
                el.channel_Code = node_id.slice(5,7) // 截取获取传感器 在对应分站上的对应通道上的编号
                el.sensor_Type = node_id.slice(7,8) // 值只有三个 A,D,E  分别代表: A - 模拟量, D - 数字量， E - 电源
            }
            else {
                el.type = '分站'
            }
        })
        return data
    }

    // 根据两个相对坐标点 返回实际的偏转角度(用于计算风向角度的)
    get_rel_rotation(end_pos,start_pos,slope) {
        // main_pos,ancil_pos : 两个长度为2的坐标数组。 slope: 线段斜率值.

        // 生成线段的方向向量
        const lineVector = [end_pos[0] - start_pos[0],end_pos[1] - start_pos[1]]
        let arrowVal = 0
        if(lineVector[0] < 0) {
            console.log('atan',Math.atan(slope))
            arrowVal = Math.atan(slope) + Math.PI
        }
        else if(lineVector[0] > 0) {
            console.log('atan',Math.atan(slope))
            arrowVal = Math.atan(slope)
        }
        else {
            if(lineVector[1] < 0) {
                arrowVal = - Math.PI * 0.5
            }
            if(lineVector[1] > 0) {
                arrowVal = Math.PI * 0.5
            }
        }
        return arrowVal
    }

    // 把所有的除底图以外的所有的gis元素的文本都隐藏掉
    hideFeatureText() {
        const staffFeatures = this.drawer.source(LayerType.SMStaff).getFeatures()
        const videoFeatures = this.drawer.source(LayerType.SMVideo).getFeatures()
        const broadcastFeatures = this.drawer.source(LayerType.SMBroadCast).getFeatures()
        const gasFeatures = this.drawer.source(LayerType.SMGas).getFeatures()
        const mergeFeatures = [...staffFeatures,...videoFeatures,...broadcastFeatures,...gasFeatures]
        mergeFeatures.forEach((f) => {
            const style = f.getStyle()
            const text = style.getText()
            text.setText('')
            style.setText(text)
            f.setStyle(style)
        })
    }
    // 把所有的除底图以外的所有的gis元素的文本都显示出来
    showFeatureText() {
        const staffFeatures = this.drawer.source(LayerType.SMStaff).getFeatures()
        const videoFeatures = this.drawer.source(LayerType.SMVideo).getFeatures()
        const broadcastFeatures = this.drawer.source(LayerType.SMBroadCast).getFeatures()
        const gasFeatures = this.drawer.source(LayerType.SMGas).getFeatures()
        const mergeFeatures = [...staffFeatures,...videoFeatures,...broadcastFeatures,...gasFeatures]
        mergeFeatures.forEach((f) => {
            const style = f.getStyle()
            const text = style.getText()
            text.setText(f.get('show_text'))
            style.setText(text)
            f.setStyle(style)
        })
    }
    // 创建 uuid
    uuid() {
        const s = [];
        const hexDigits = "0123456789abcdef";
        for (let i = 0; i < 32; i++) {
            s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
        }
        s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
        s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
        s[8] = s[13] = s[18] = s[23];
        const uuid = s.join("");
        return uuid;
    }

}